package handler

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/go-ego/gse"
	"io"
	"math"
	"strings"
	"time"
	"unicode"

	"demo/es"
	"demo/model"
	"github.com/elastic/go-elasticsearch/v8/esapi"
)

var Seg gse.Segmenter

const indexName = "products"

// CreateProduct 创建文档
func CreateProduct(product model.Product) (string, error) {
	body, _ := json.Marshal(product)

	req := esapi.IndexRequest{
		Index:      indexName,
		DocumentID: "", // 自动生成 ID
		Body:       io.NopCloser(bytes.NewReader(body)),
		Refresh:    "true",
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return "", err
	}
	defer res.Body.Close()

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return "", err
	}

	return fmt.Sprintf("%v", result["_id"]), nil
}

// BatchCreateProducts 批量创建文档
func BatchCreateProducts(products []model.Product) ([]string, error) {
	var buf bytes.Buffer

	// 构建批量请求体
	for _, product := range products {
		meta := map[string]interface{}{
			"index": map[string]interface{}{
				"_index": indexName,
			},
		}
		metaJSON, _ := json.Marshal(meta)
		productJSON, _ := json.Marshal(product)

		buf.Write(append(metaJSON, "\n"...))
		buf.Write(append(productJSON, "\n"...))
	}

	// 执行批量请求
	req := esapi.BulkRequest{
		Body:    io.NopCloser(&buf),
		Refresh: "true",
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, fmt.Errorf("error response: %s", res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	// 提取成功插入的文档 ID
	var ids []string
	for _, item := range result["items"].([]interface{}) {
		if itemMap, ok := item.(map[string]interface{}); ok {
			if indexItem, ok := itemMap["index"].(map[string]interface{}); ok {
				if id, ok := indexItem["_id"].(string); ok {
					ids = append(ids, id)
				}
			}
		}
	}

	return ids, nil
}

// GetProduct 获取文档
func GetProduct(id string) (*model.Product, error) {
	req := esapi.GetRequest{
		Index:      indexName,
		DocumentID: id,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, fmt.Errorf("error response: %s", res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	source, ok := result["_source"].(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("no source found")
	}

	product := &model.Product{
		Title:       fmt.Sprintf("%v", source["title"]),
		ProductId:   fmt.Sprintf("%v", source["productId"]),
		ProductType: int(source["productType"].(float64)),
		SKUID:       fmt.Sprintf("%v", source["skuid"]),
		Spec:        fmt.Sprintf("%v", source["spec"]),
		SupplierId:  int64(source["supplierId"].(float64)),
		Supplier:    fmt.Sprintf("%v", source["supplier"]),
		Barcode:     fmt.Sprintf("%v", source["barcode"]),
		CreatedAt:   time.Time{},
		UpdatedAt:   time.Time{},
		Status:      int(source["status"].(float64)),
	}

	// 解析时间字段
	if createdAt, ok := source["createdAt"].(string); ok {
		product.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
	}
	if updatedAt, ok := source["updatedAt"].(string); ok {
		product.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)
	}

	return product, nil
}

// UpdateProduct 更新文档
func UpdateProduct(id string, product model.Product) error {
	body, _ := json.Marshal(map[string]interface{}{
		"doc": product,
	})

	req := esapi.UpdateRequest{
		Index:      indexName,
		DocumentID: id,
		Body:       io.NopCloser(bytes.NewReader(body)),
		Refresh:    "true",
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	return nil
}

// DeleteProduct 删除文档
func DeleteProduct(id string) error {
	req := esapi.DeleteRequest{
		Index:      indexName,
		DocumentID: id,
		Refresh:    "true",
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	return nil
}

// SearchProducts 全文搜索产品
func SearchProducts(query string, pageNum, pageSize int) ([]model.Product, int64, error) {
	// 分页参数校验
	if pageNum < 1 {
		pageNum = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	// 分词处理
	tokens := Seg.CutSearch(query)
	tokens = Seg.Trim(tokens)
	fmt.Print("tokens:")
	fmt.Println(tokens)

	if len(tokens) == 0 {
		return nil, 0, fmt.Errorf("分词后无有效词元，请检查输入内容")
	}

	// 构建 should 子句
	var shouldClauses []map[string]interface{}
	for _, token := range tokens {
		shouldClauses = append(shouldClauses, map[string]interface{}{
			"match": map[string]interface{}{
				"title": map[string]interface{}{
					"query":     token,
					"fuzziness": "AUTO",
				},
			},
		})
	}

	// 计算 minimum_should_match（10%）`
	minMatch := fmt.Sprintf("%d", int(math.Ceil(float64(len(tokens))*0.70)))

	// 构建查询体
	queryBody := map[string]interface{}{
		"from": (pageNum - 1) * pageSize,
		"size": pageSize,
		"query": map[string]interface{}{
			"bool": map[string]interface{}{
				"should":               shouldClauses,
				"minimum_should_match": minMatch,
			},
		},
	}

	// 序列化为 JSON 并发送请求
	var buf bytes.Buffer
	body, _ := json.Marshal(queryBody)
	buf.Write(body)

	req := esapi.SearchRequest{
		Index: []string{indexName},
		Body:  io.NopCloser(&buf),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, 0, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, 0, fmt.Errorf("error response: %s", res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, 0, err
	}

	// 提取搜索结果
	var products []model.Product
	hits := result["hits"].(map[string]interface{})["hits"].([]interface{})
	total := int64(result["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64))

	for _, hit := range hits {
		source := hit.(map[string]interface{})["_source"].(map[string]interface{})
		product := model.Product{
			Title:       fmt.Sprintf("%v", source["title"]),
			ProductId:   fmt.Sprintf("%v", source["productId"]),
			ProductType: int(source["productType"].(float64)),
			SKUID:       fmt.Sprintf("%v", source["skuid"]),
			Spec:        fmt.Sprintf("%v", source["spec"]),
			SupplierId:  int64(source["supplierId"].(float64)),
			Supplier:    fmt.Sprintf("%v", source["supplier"]),
			Barcode:     fmt.Sprintf("%v", source["barcode"]),
			CreatedAt:   time.Time{},
			UpdatedAt:   time.Time{},
			Status:      int(source["status"].(float64)),
		}

		// 解析时间字段
		if createdAt, ok := source["createdAt"].(string); ok {
			product.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
		}
		if updatedAt, ok := source["updatedAt"].(string); ok {
			product.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)
		}

		products = append(products, product)
	}

	return products, total, nil
}

// SearchProductsCombined 结合 match 和 fuzzy 的组合查询
func SearchProductsCombined(query string, field string) ([]model.Product, error) {
	var buf bytes.Buffer
	// 添加分词处理逻辑
	query = processQuery(query)
	query = `{
		"query": {
			"bool": {
				"should": [
					{
						"match": {
							"` + field + `": {
								"query": "` + query + `",
								"fuzziness": "AUTO"
							}
						}
					},
					{
						"fuzzy": {
							"` + field + `": {
								"value": "` + query + `",
								"fuzziness": "AUTO"
							}
						}
					}
				]
			}
		}
	}`
	buf.WriteString(query)

	req := esapi.SearchRequest{
		Index: []string{indexName},
		Body:  io.NopCloser(&buf),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, fmt.Errorf("error response: %s", res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	// 提取搜索结果
	var products []model.Product
	hits := result["hits"].(map[string]interface{})["hits"].([]interface{})
	for _, hit := range hits {
		source := hit.(map[string]interface{})["_source"].(map[string]interface{})
		product := model.Product{
			Title:       fmt.Sprintf("%v", source["title"]),
			ProductId:   fmt.Sprintf("%v", source["productId"]),
			ProductType: int(source["productType"].(float64)),
			SKUID:       fmt.Sprintf("%v", source["skuid"]),
			Spec:        fmt.Sprintf("%v", source["spec"]),
			SupplierId:  int64(source["supplierId"].(float64)),
			Supplier:    fmt.Sprintf("%v", source["supplier"]),
			Barcode:     fmt.Sprintf("%v", source["barcode"]),
			CreatedAt:   time.Time{},
			UpdatedAt:   time.Time{},
			Status:      int(source["status"].(float64)),
		}

		// 解析时间字段
		if createdAt, ok := source["createdAt"].(string); ok {
			product.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
		}
		if updatedAt, ok := source["updatedAt"].(string); ok {
			product.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)
		}

		products = append(products, product)
	}

	return products, nil
}

// processQuery 处理查询字符串，添加分词逻辑
func processQuery(query string) string {
	// 简单分词逻辑：将中英文混合字符串按空格和标点符号分割
	// 实际项目中可以替换为更复杂的分词算法或调用外部分词服务
	words := []string{}
	for _, word := range strings.FieldsFunc(query, func(r rune) bool {
		return !unicode.IsLetter(r) && !unicode.IsNumber(r)
	}) {
		if word != "" {
			words = append(words, word)
		}
	}
	return strings.Join(words, " ")
}
